import {existsSync, readFileSync, writeFileSync} from 'fs';
import dotProp from 'dot-prop';

type keysType =
  | 'concurrency'
  | 'saveLayout'
  | 'saveLayout.track'
  | 'saveLayout.album'
  | 'saveLayout.artist'
  | 'saveLayout.playlist'
  | 'trackNumber'
  | 'coverSize.128'
  | 'coverSize.320'
  | 'coverSize.flac'
  | 'cookies.arl';

type configType = {
  concurrency: number;
  saveLayout: {
    track: string;
    album: string;
    artist: string;
    playlist: string;
  };
  trackNumber: boolean;
  coverSize: {
    '128': number;
    '320': number;
    flac: number;
  };
  cookies: {
    arl: string;
  };
};

const defaultConfig: configType = {
  concurrency: 4,
  saveLayout: {
    track: 'Music/{ALB_TITLE}/{SNG_TITLE}',
    album: 'Music/{ALB_TITLE}/{SNG_TITLE}',
    artist: 'Music/{ALB_TITLE}/{SNG_TITLE}',
    playlist: 'Playlist/{TITLE}/{SNG_TITLE}',
  },
  trackNumber: true,
  coverSize: {
    '128': 500,
    '320': 500,
    flac: 1000,
  },
  cookies: {
    arl:
      '9a71280a1354b252f21dbb5640899287973872f27073f8fd908a0e685538fef5e7f4d52af18fc076837ba4c4eee0f002e9643c63e964a256e3508be249b91151a1197a8c6ec845f62bcb0b964ba09e60b3ef0f75176487577d4d4458af7edb0a',
  },
};

const configFile = 'd-fi.config.json';

class Config {
  private store: configType;

  constructor() {
    this.store = existsSync(configFile)
      ? {...defaultConfig, ...JSON.parse(readFileSync(configFile, 'utf-8'))}
      : defaultConfig;
  }

  /**
   * Get an item.
   * @param key - The key of the item to get.
   * @param defaultValue - The default value if the item does not exist.
   */
  get(key: keysType, defaultValue?: string | boolean | number) {
    return dotProp.get(this.store, key, defaultValue);
  }

  /**
   * Set an item or multiple items at once.
   * @param {key|object} - You can use [dot-notation](https://github.com/sindresorhus/dot-prop) in a key to access nested properties. Or a hashmap of items to set at once.
   * @param value - Must be JSON serializable. Trying to set the type `undefined`, `function`, or `symbol` will result in a `TypeError`.
   */
  set(key: keysType, value: string | boolean | number) {
    dotProp.set(this.store, key, value);
    writeFileSync(configFile, JSON.stringify(this.store, null, 2));
    return configFile;
  }

  /**
   * Delete an item.
   * @param key - The key of the item to delete.
   */
  delete(key: keysType) {
    dotProp.delete(this.store, key);
  }
}

export default Config;
